﻿/*
 * Created by SharpDevelop.
 * User: issuser
 * Date: 2010-12-6
 * Time: 17:36
 * 
 * To change this template use Tools | Options | Coding | Edit Standard Headers.
 */
using System;
using NLite.Data;

using System.Data;
using NLite.Data.SqlTypes;

namespace NLite.Data.Dialect
{
	public class MsSql2005Dialect : MsSql2000Dialect
    {
        public MsSql2005Dialect()
        {
        }

        protected override void RegisterColumnTypes()
        {
            base.RegisterColumnTypes();
            RegisterColumnType(DbTypeCode.String, 1073741823, "NVARCHAR(MAX)");
            RegisterColumnType(DbTypeCode.AnsiString, 2147483647, "VARCHAR(MAX)");
            RegisterColumnType(DbTypeCode.Binary, 2147483647, "VARBINARY(MAX)");
        }

        public override bool SupportsCollectionOperation(CollectionOperator type)
        {
            return true;
        }

        public override string FormatCollectionOperation(CollectionOperator type)
        {
            if (type == CollectionOperator.Minus)
                type = CollectionOperator.Except;
            return base.FormatCollectionOperation(type);
        }

        protected override void BuildSelectWithOffset(NodeWriter visitor, SelectNode select)
        {
            var offset = select.PageIndex;

            var firstResult = offset + 1;

            var orderByClause = (OrderNode)select.OrderBy.Clone();

            if (orderByClause.Items.Count == 0)
            {
                orderByClause.Items.Add(new OrderItemNode(Projection.Native("CURRENT_TIMESTAMP"), OrderDirection.Asc));
            }

            string orderBy = orderByClause.Result.Text;

            string rowCountFieldSql = "ROW_NUMBER() OVER(" + orderBy + ") as RowNumber";
            var rowCountField = Projection.Native(rowCountFieldSql);

            string queryName = "[__pagedQuery__]";

            var innerSelect = (SelectNode)select.Clone();

            innerSelect.Projections.Insert(0, rowCountField);

            innerSelect.PageSize = -1;
            innerSelect.PageIndex = 0;
            innerSelect.OrderBy.Items.Clear();


            var outerSelectBuilder = new SelectNode(queryName);
            outerSelectBuilder.Projections.Add(Projection.Native("*"));
            outerSelectBuilder.Where.AddCriterion(Criterion.Native("RowNumber>=" + firstResult), LogicOperator.And);
            if (select.PageSize >= 0)
            {
                var lastResult = offset + select.PageSize;
                if (lastResult < 0) lastResult = Int32.MaxValue;

                outerSelectBuilder.Where.AddCriterion(Criterion.Native("RowNumber<=" + lastResult), LogicOperator.And);
            }


            visitor.Builder.Append("WITH ");
            visitor.Builder.Append(queryName);
            visitor.Builder.Append(" AS (\n");
            visitor.Builder.AppendLine(Text.Indentation.Inner);

            base.BuildSelect(visitor, innerSelect);
            visitor.Builder.AppendLine(Text.Indentation.Outer);
            visitor.Builder.Append(")\n");
            visitor.Builder.AppendLine();
            base.BuildSelect(visitor, outerSelectBuilder);
        }
    }
}
